﻿using System;
using System.Collections.Generic;
using DevExpress.ExpressApp.Xpo;
using DevExpress.Persistent.Validation;
using DevExpress.Xpo.DB;
using Microsoft.SqlServer.Management.Smo;
using Xpand.ExpressApp.WorldCreator.Core;
using System.Linq;
using Xpand.Persistent.Base.PersistentMetaData;
using Xpand.Persistent.Base.PersistentMetaData.PersistentAttributeInfos;
using Xpand.Utils.Helpers;

namespace Xpand.ExpressApp.WorldCreator.SqlDBMapper {
    public class AttributeMapper {
        readonly ForeignKeyCalculator _foreignKeyCalculator = new ForeignKeyCalculator();
        readonly XPObjectSpace _objectSpace;


        public AttributeMapper(XPObjectSpace objectSpace) {
            _objectSpace = objectSpace;
        }



        public List<IPersistentAttributeInfo> Create(Column column, IPersistentMemberInfo owner, DataTypeMapper dataTypeMapper) {
            var persistentAttributeInfos = new List<IPersistentAttributeInfo>();

            if (owner.CodeTemplateInfo.CodeTemplate.TemplateType == TemplateType.XPOneToOnePropertyMember)
                return persistentAttributeInfos;
            if (column.InPrimaryKey) {
                if (owner.Owner.CodeTemplateInfo.CodeTemplate.TemplateType != TemplateType.Struct) {
                    persistentAttributeInfos.Add(GetPersistentKeyAttribute(column));
                }
            }
            if (!column.Nullable && !column.InPrimaryKey) {
                persistentAttributeInfos.Add(GetPersistentRuleRequiredFieldAttribute(column));
            }
            if (dataTypeMapper.GetDataType(column) == DBColumnType.String) {
                persistentAttributeInfos.Add(GetPersistentSizeAttribute(column));
            }
            if (IsSimpleForeignKey(column) || ((IsCompoundPrimaryKey(owner, column) && column.IsForeignKey)))
                persistentAttributeInfos.Add(GetPersistentAssociationAttribute(column));
            //            if (owner.Owner.CodeTemplateInfo.CodeTemplate.TemplateType!=TemplateType.Struct)

            var persistentPersistentAttribute = GetPersistentPersistentAttribute(column.Name);
            if (IsSimpleForeignKey(column) && IsCompoundForeignKey(column))
                persistentPersistentAttribute.MapTo = String.Empty;
            persistentAttributeInfos.Add(persistentPersistentAttribute);
            return persistentAttributeInfos;
        }

        bool IsCompoundForeignKey(Column column) {
            var foreignKey = _foreignKeyCalculator.GetForeignKey(column);
            return foreignKey.Columns.Count > 1;
        }

        bool IsCompoundPrimaryKey(IPersistentMemberInfo owner, Column column) {
            return owner.Owner.CodeTemplateInfo.CodeTemplate.TemplateType == TemplateType.Struct && column.InPrimaryKey;
        }

        bool IsSimpleForeignKey(Column column) {
            return (column.IsForeignKey && !(column.InPrimaryKey));
        }

        IPersistentAssociationAttribute GetPersistentAssociationAttribute(Column column) {
            var persistentAssociationAttribute = _objectSpace.CreateWCObject<IPersistentAssociationAttribute>();
            persistentAssociationAttribute.AssociationName = _foreignKeyCalculator.GetForeignKeyName(column.Name, (Table)column.Parent);
            return persistentAssociationAttribute;
        }

        IPersistentSizeAttribute GetPersistentSizeAttribute(Column column) {
            var persistentSizeAttribute = _objectSpace.CreateWCObject<IPersistentSizeAttribute>();
            persistentSizeAttribute.Size = column.DataType.MaximumLength;
            return persistentSizeAttribute;
        }

        IPersistentRuleRequiredFieldAttribute GetPersistentRuleRequiredFieldAttribute(Column column) {
            var persistentRuleRequiredFieldAttribute = _objectSpace.CreateWCObject<IPersistentRuleRequiredFieldAttribute>();
            persistentRuleRequiredFieldAttribute.Context = DefaultContexts.Save.ToString();
            persistentRuleRequiredFieldAttribute.ID = "RuleRequired for " + column.Name + " at " +
                                                      ((Table)column.Parent).Name;
            return persistentRuleRequiredFieldAttribute;
        }

        IPersistentKeyAttribute GetPersistentKeyAttribute(Column column) {
            var persistentAttributeInfo = _objectSpace.CreateWCObject<IPersistentKeyAttribute>();
            persistentAttributeInfo.AutoGenerated = column.Identity;
            return persistentAttributeInfo;
        }


        public XPObjectSpace ObjectSpace {
            get { return _objectSpace; }
        }

        public List<IPersistentAttributeInfo> Create(Table table, IPersistentClassInfo owner, IMapperInfo mapperInfo) {
            var persistentAttributeInfos = new List<IPersistentAttributeInfo>();
            if (owner.TypeAttributes.OfType<IPersistentPersistentAttribute>().FirstOrDefault() == null)
                persistentAttributeInfos.Add(GetPersistentPersistentAttribute(table.Name));
            if (!(string.IsNullOrEmpty(mapperInfo.NavigationPath)) && owner.TypeAttributes.OfType<IPersistentNavigationItemAttribute>().FirstOrDefault() == null) {
                var persistentNavigationItemAttribute = ObjectSpace.CreateWCObject<IPersistentNavigationItemAttribute>();
                var cleanName = owner.Name.CleanCodeName();
                persistentNavigationItemAttribute.Path = mapperInfo.NavigationPath + "/" + cleanName;
                persistentNavigationItemAttribute.ViewId = cleanName + "_ListView";
                persistentAttributeInfos.Add(persistentNavigationItemAttribute);
            }
            return persistentAttributeInfos;
        }

        IPersistentPersistentAttribute GetPersistentPersistentAttribute(string name) {
            var persistentPersistentAttribute = ObjectSpace.CreateWCObject<IPersistentPersistentAttribute>();
            persistentPersistentAttribute.MapTo = name;
            return persistentPersistentAttribute;
        }

        public void Create(IPersistentAssemblyInfo persistentAssemblyInfo, IDataStoreLogonObject dataStoreLogonObject) {
            if (persistentAssemblyInfo.PersistentClassInfos.Any()) {
                var persistentAssemblyDataStoreAttributeInfo = _objectSpace.CreateWCObject<IPersistentAssemblyDataStoreAttributeInfo>();
                persistentAssemblyDataStoreAttributeInfo.DataStoreLogon = dataStoreLogonObject;
                persistentAssemblyDataStoreAttributeInfo.PersistentClassInfo = persistentAssemblyInfo.PersistentClassInfos[0];
                persistentAssemblyInfo.Attributes.Add(persistentAssemblyDataStoreAttributeInfo);
            }
        }
    }
}